home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / misc / pclta-1.000 / pclta-1 / hostappl / ni_msg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-27  |  29.3 KB  |  790 lines

  1. /*
  2.  * ni_msg.c,v 1.1 1996/05/27 15:57:42 miksic Exp
  3.  */
  4.  
  5. /* NI_MSG.C -- LONWORKS host application message send and receive functions.
  6.  * Copyright (c) 1993 by Echelon Corporation.
  7.  * All Rights Reserved.
  8.  *
  9.  * Example LONWORKS network interface message send/receive functions.
  10.  * Functions to initialize the network interface are also included.
  11.  * These are general-purpose functions that may be used with any
  12.  * host application.
  13.  */
  14.  
  15. /****************************** Include Files *******************************/
  16.  
  17. #include "ldv.h"                    /* Standard network driver functions   */
  18. #include "ni_msg.h"                 /* Network interface data structures   */
  19. #include <stdio.h>                  /* For printf()                        */
  20. #include <string.h>                 /* For strlen(), strncpy()             */
  21. #include <stdlib.h>                 /* For malloc(), free(), exit()        */
  22. #include <time.h>
  23. extern boolean verbose_flag;
  24.  
  25. /*
  26.  ****************************************************************************
  27.  * Default message buffers.
  28.  * Assume explicit addressing is enabled in network interface.
  29.  ****************************************************************************
  30.  */
  31.  
  32. ExpAppBuffer  msg_in;               /* Incoming message buffer       */
  33. ExpAppBuffer  msg_out;              /* Outgoing message buffer       */
  34.  
  35. struct msg_list_struct {
  36.     struct msg_list_struct * next_msg;        /* linked list pointer */
  37.     byte                     length;
  38.     ExplicitAddr             addr;
  39.     ServiceType              service;        /* for pending list messages */
  40.     boolean                  priority;       /*           "               */
  41.     boolean                  auth;           /*           "               */
  42.     byte                     tag;            /*           "               */
  43.     byte                     data[ 1 ];      /* followed by the real data */
  44. };                 /* linked list of pending messages */
  45.  
  46. typedef struct msg_list_struct msg_list;
  47. msg_list    * response_list = NULL;       /* List of pending responses */
  48. msg_list    * pending_list  = NULL;       /* List of other incoming msgs */
  49.  
  50. /* These are from the last request message passed back to the application */
  51. /* The application is expected to call ni_send_response( ) */
  52.  
  53. boolean     last_request_priority;
  54. byte        last_request_tag;
  55.  
  56. const time_t niWAIT_TIME = 5;   /* Wait time for network interface */
  57. const byte msg_tag_any = 14;
  58.    /* use this tag for explicitly addressed send_msg_wait */
  59.  
  60. const char  * svc_table[ 4 ]
  61.     = { "Ackd", "Unackd/rpt", "Unackd", "Request" };
  62.  
  63. void init_response_list( void );    /* prototypes */
  64. void init_pending_list( void );
  65. NI_Code ni_get_msg( time_t wait );
  66. NI_Code ni_put_msg( void );
  67. void ni_ldv_error_display(const char * s, LDVCode ldv_error);
  68.                                      /* Display a network driver error   */
  69. void save_response( byte msg_length );
  70. void save_pending( byte msg_length );
  71.  
  72. void init_response_list( void );
  73.  
  74. /*
  75.  ****************************************************************************
  76.  * Network driver error strings.
  77.  ****************************************************************************
  78.  */
  79.  
  80. static char *ldv_error_strings[] = {
  81.     "No error",
  82.     "Network driver not found",
  83.     "Network interface already open",
  84.     "Network interface not open",
  85.     "Network interface hardware error",
  86.     "Invalid device ID",
  87.     "No messages buffered for read",
  88.     "No message buffers available for write",
  89.     "Network interface being initialized"
  90. };
  91.  
  92. /*
  93.  ****************************************************************************
  94.  * Network interface error strings.
  95.  ****************************************************************************
  96.  */
  97.  
  98. static char *ni_error_strings[] = {
  99.     "No error",
  100.     "Device name not specified",
  101.     "Could not open network driver",
  102.     "Could not initialize network driver",
  103.     "Could not reset network driver",
  104.     "Network driver error",
  105.     "No response messages left",
  106.     "Network interface reset failed",
  107.     "No response from network interface, command timed out",
  108.     "Uplink command received from network interface",
  109.     "Internal error detected"
  110. };
  111.  
  112. /***************************** Local Variables ******************************/
  113.  
  114. static const char * current_device_name;
  115.                     /* Currently open network driver name */
  116. static LNI ni_handle = -1;
  117.                /* Network driver handle - initially closed */
  118.  
  119. /************************************************************************/
  120.  
  121. NI_Code ni_send_msg_wait(
  122.     ServiceType       service,          /* ACKD, UNACKD_RPT, UNACKD, REQUEST */
  123.     const SendAddrDtl * out_addr,       /* address of outgoing message */
  124.     const MsgData     * out_data,       /* data of outgoing message */
  125.     int               out_length,       /* length of outgoing message */
  126.     boolean           priority,         /* outgoing message priority */
  127.     boolean           out_auth,         /* outgoing message authenticated */
  128.     ComplType       * completion,       /* MSG_SUCCEEDS or MSG_FAILS */
  129.     int             * num_responses,    /* number of received responses */
  130.     RespAddrDtl     * in_addr,          /* address of first response */
  131.     MsgData         * in_data,          /* data of first response */
  132.     int             * in_length         /* length of first response */
  133. ) {
  134.  
  135.     boolean         local;              // Is it addressed to net intfc?
  136.     boolean         implicit;           // Does it use implicit addressing?
  137.     NI_Code         ni_error;
  138.     int             response_count = 0;
  139.     ComplType       cmpl_code;
  140.     byte            incoming_tag;
  141.     byte            outgoing_tag;
  142.     byte            msg_length;
  143.  
  144.     if( num_responses ) * num_responses = 0;    /* clear count */
  145.     init_response_list( );      /* clear out any responses from previous */
  146.  
  147.     implicit = ( out_addr->im.type == IMPLICIT );
  148.     outgoing_tag = implicit ? out_addr->im.msg_tag : msg_tag_any;
  149.     local = ( out_addr->lc.type == LOCAL );
  150.  
  151.     ni_msg_hdr_init( out_length,     /* msg size */
  152.                   service,          /* service type */
  153.                   priority,         /* priority */
  154.                   local,            /* addressed to net intfc */
  155.                   out_auth,         /* authenticated */
  156.                   implicit,         /* explicitly addressed */
  157.                   outgoing_tag  );
  158.  
  159.     if( !implicit )
  160.         msg_out.addr.snd = * out_addr;      /* destination address */
  161.     memcpy( &msg_out.data.exp, out_data, out_length );    /* outgoing data */
  162.     if( ( ni_error = ni_put_msg( ) ) != NI_OK )        /* send message */
  163.         return( ni_error );
  164.  
  165.     if( local && service != REQUEST ) {     // local, not req/resp, all done
  166.         if( completion ) * completion = MSG_SUCCEEDS;
  167.         return( NI_OK );
  168.     }
  169.  
  170.     for( ;; ) {         /* look for completion events and responses */
  171.         if( ( ni_error = ni_get_msg( niWAIT_TIME ) ) != NI_OK )
  172.              return( ni_error );
  173.  
  174.         msg_length = msg_in.msg_hdr.exp.length;
  175.         incoming_tag = msg_in.msg_hdr.exp.tag;
  176.  
  177.         if( msg_in.msg_hdr.exp.response ) {     /* a response */
  178.             if( incoming_tag != outgoing_tag ) {
  179.                 save_pending( msg_length );    /* a response to another tag */
  180.                 continue;           /* keep looking for completion */
  181.             }
  182.                             /* a response to our tag */
  183.             if( !response_count ) {  /* first response, copy it */
  184.                 if( in_addr ) * in_addr = msg_in.addr.rsp;
  185.                 if( in_data ) memcpy( in_data, &msg_in.data, msg_length );
  186.                 if( in_length ) * in_length = msg_length;
  187.             } else save_response( msg_length );
  188.                     /* subsequent response to our tag */
  189.  
  190.             response_count++;           /* got another one */
  191.  
  192.             if( ! local ) continue; /* not local, keep looking for completion */
  193.  
  194.           /* no completion events for local msgs, only one response */
  195.  
  196.             if( completion ) * completion = MSG_SUCCEEDS;
  197.             if( num_responses ) * num_responses = response_count;
  198.             return( NI_OK );         /* This transaction is done */
  199.         }
  200.         /* here if incoming is not a response */
  201.  
  202.         cmpl_code = msg_in.msg_hdr.exp.cmpl_code;
  203.         switch( cmpl_code ) {
  204.             case MSG_NOT_COMPL:
  205.                 save_pending( msg_length ); /* some other incoming message */
  206.                 continue;           /* keep looking for completion */
  207.  
  208.             case MSG_FAILS:
  209.             case MSG_SUCCEEDS:
  210.                 /* found the completion event */
  211.                 if( incoming_tag != outgoing_tag ) return( NI_INTERNAL_ERR );
  212.                 if( completion ) * completion = cmpl_code;
  213.                 if( num_responses ) * num_responses = response_count;
  214.                 return( NI_OK );         /* This transaction is done */
  215.  
  216.             default:
  217.                 return( NI_INTERNAL_ERR );   /* Invalid completion code */
  218.         }  /* end switch( cmpl_code ) */
  219.     }   /* end for( ;; ) */
  220. }
  221.  
  222. /************************************************************************/
  223.  
  224. NI_Code ni_get_next_response(         /* get subsequent responses here */
  225.     RespAddrDtl     * in_addr,
  226.     MsgData         * in_data,
  227.     int             * in_length
  228. ) {
  229.     byte          msg_length;
  230.     msg_list    * next_response;
  231.  
  232.     if( response_list == NULL ) return( NI_NO_RESPONSES );
  233.  
  234.     msg_length = response_list->length;
  235.     if( in_addr ) * in_addr = response_list->addr.rsp;
  236.     if( in_data ) memcpy( in_data, response_list->data, msg_length );
  237.     if( in_length ) * in_length = msg_length;
  238.  
  239.     next_response = response_list->next_msg;
  240.     free( response_list );
  241.     response_list = next_response;
  242.     return( NI_OK );
  243. }
  244. /************************************************************************/
  245.  
  246.  
  247. NI_Code ni_receive_msg(
  248.     ServiceType     * service,        /* ACKD, UNACKD_RPT, UNACKD, REQUEST */
  249.     RcvAddrDtl      * in_addr,        /* address of incoming msg */
  250.     MsgData         * in_data,        /* data of incoming msg */
  251.     int             * in_length,      /* length of incoming msg */
  252.     boolean         * in_auth
  253. ) {
  254.     msg_list        * next_pending;
  255.     NI_Code         ni_error;
  256.     byte            msg_length;
  257.  
  258.     if( pending_list != NULL ) {    /* got one squirreled away */
  259.         if( service ) * service = pending_list->service;
  260.         if( in_addr ) * in_addr = pending_list->addr.rcv;
  261.         if( in_auth ) * in_auth = pending_list->auth;
  262.         if( in_data ) memcpy( in_data, pending_list->data, pending_list->length );
  263.         if( in_length ) * in_length = pending_list->length;
  264.         if( pending_list->service == REQUEST ) {
  265.             last_request_priority = pending_list->priority;
  266.             last_request_tag = pending_list->tag;
  267.         }           /* save for a response from the application */
  268.  
  269.         next_pending = pending_list->next_msg;  /* unhook pending message */
  270.         free( pending_list );
  271.         pending_list = next_pending;
  272.         return( NI_OK );
  273.     }
  274.  
  275.     /* nothing on the pending list, see if there is an incoming message */
  276.  
  277.     if( ( ni_error = ni_get_msg( 0 ) ) != NI_OK ) return( ni_error );
  278.  
  279.     if( msg_in.msg_hdr.exp.response ) {
  280.         printf( "Received a belated response message\n" );
  281.         return( NI_UPLINK_CMD );
  282.     }
  283.     switch( msg_in.msg_hdr.exp.cmpl_code ) {
  284.         case MSG_FAILS:
  285.             printf( "Received a failure completion event\n" );
  286.             return( NI_UPLINK_CMD );
  287.         case MSG_SUCCEEDS:
  288.         printf( "Received a success completion event\n" );
  289.             return( NI_UPLINK_CMD );
  290.     }       // fall through for non-completion
  291.  
  292.     msg_length = msg_in.msg_hdr.exp.length;
  293.     if( service ) * service = msg_in.msg_hdr.exp.st;
  294.     if( in_length ) * in_length = msg_length;
  295.     if( in_addr ) * in_addr = msg_in.addr.rcv;
  296.     if( in_auth ) * in_auth = msg_in.msg_hdr.exp.auth;
  297.     if( in_data ) memcpy( in_data, &msg_in.data, msg_length );
  298.  
  299.     if( msg_in.msg_hdr.exp.st == REQUEST ) {
  300.         last_request_priority = msg_in.msg_hdr.exp.priority;
  301.         last_request_tag = msg_in.msg_hdr.exp.tag;
  302.     }           /* save for a response */
  303.  
  304.     return( NI_OK );
  305. }
  306. /************************************************************************/
  307.  
  308.  
  309. NI_Code ni_send_response(         /* send response to last received request */
  310.     MsgData       * out_data,     /* data for outgoing response */
  311.     int             out_length    /* length of outgoing response */
  312. ) {
  313.     NI_Code         ni_error;
  314.  
  315.     msg_out.ni_hdr.q.queue        = last_request_priority ? niNTQ_P : niNTQ;
  316.     msg_out.ni_hdr.q.q_cmd        = niCOMM;
  317.     msg_out.ni_hdr.q.length       = sizeof( ExpMsgHdr )
  318.                                   + sizeof( ExplicitAddr) + out_length;
  319.     msg_out.msg_hdr.exp.tag       = last_request_tag;    /* use same tag */
  320.     msg_out.msg_hdr.exp.auth      = 0;
  321.     msg_out.msg_hdr.exp.response  = 1;       /* make it a response */
  322.     msg_out.msg_hdr.exp.st        = REQUEST;
  323.     msg_out.msg_hdr.exp.pool      = 0;      /* Must be zero             */
  324.     msg_out.msg_hdr.exp.alt_path  = 0;      /* Use default path         */
  325.     msg_out.msg_hdr.exp.addr_mode = 0;      /* IMplicit addressing      */
  326.     msg_out.msg_hdr.exp.cmpl_code = MSG_NOT_COMPL; /* Zero              */
  327.     msg_out.msg_hdr.exp.path      = 0;      /* Use primary path         */
  328.     msg_out.msg_hdr.exp.priority  = last_request_priority;
  329.     msg_out.msg_hdr.exp.length    = out_length;
  330.  
  331.     memcpy( &msg_out.data.exp, out_data, out_length );    /* outgoing data */
  332.     ni_error = ni_put_msg( );       /* send message */
  333.     return( ni_error );
  334. };
  335.  
  336. /************************************************************************/
  337.  
  338. void init_response_list( void ) {   /* initialize list of responses */
  339.  
  340.     msg_list    * next_response;
  341.  
  342.     while( response_list != NULL ) {
  343.         next_response = response_list->next_msg;
  344.         free( response_list );
  345.         response_list = next_response;
  346.    }
  347. }
  348. /************************************************************************/
  349.  
  350. void init_pending_list( void ) {
  351.       /* initialize list of pending messages */
  352.  
  353.     msg_list    * next_pending;
  354.  
  355.     while( pending_list != NULL ) {
  356.         next_pending = pending_list->next_msg;
  357.         free( pending_list );
  358.         pending_list = next_pending;
  359.    }
  360. }
  361. /************************************************************************/
  362.  
  363. void save_response( byte msg_length ) {
  364.      /* come here to save any responses beyond the first for group
  365.         addressed request/response service */
  366.  
  367.     msg_list    * next_response;
  368.  
  369.     next_response = ( msg_list * ) malloc( sizeof( msg_list ) + msg_length );
  370.     if( next_response == NULL ) {
  371.         printf( "Out of memory in save_response\n" );
  372.         exit( 1 );      /* Unfriendly recovery */
  373.     }
  374.  
  375.     next_response->next_msg = response_list;    /* link chain */
  376.     response_list = next_response;
  377.     next_response->length = msg_length;         /* save response */
  378.     next_response->addr = msg_in.addr;
  379.     memcpy( next_response->data, &msg_in.data, msg_length );
  380. }
  381. /************************************************************************/
  382.  
  383. void save_pending( byte msg_length ) {
  384.     /* come here to squirrel away an incoming message that is not part
  385.        of the current transaction */
  386.     msg_list    * next_pending;
  387.  
  388.     next_pending = ( msg_list * )malloc( sizeof( msg_list ) + msg_length );
  389.     if( next_pending == NULL ) {
  390.         printf( "Out of memory in save_pending\n" );
  391.         exit( 1 );      /* Unfriendly recovery */
  392.     }
  393.  
  394.     next_pending->next_msg = pending_list;    /* link chain */
  395.     pending_list = next_pending;
  396.     next_pending->length = msg_length;         /* save pending */
  397.     next_pending->addr = msg_in.addr;
  398.     next_pending->service = msg_in.msg_hdr.exp.st;
  399.     next_pending->priority = msg_in.msg_hdr.exp.priority;
  400.     next_pending->auth = msg_in.msg_hdr.exp.auth;
  401.     memcpy( next_pending->data, &msg_in.data, msg_length );
  402. }
  403.  
  404. /*
  405.  ****************************************************************************
  406.  * ni_get_msg().  Receive a message in msg_in.  Return when a message
  407.  * is received, or if the wait timer times out
  408.  ****************************************************************************
  409.  */
  410.  
  411. NI_Code ni_get_msg( time_t wait ) {   /* how long to wait for input */
  412.  
  413.     LDVCode ldv_error = LDV_OK;
  414.     time_t  deadline;
  415.  
  416.     if( wait ) deadline = time( NULL ) + wait;
  417.  
  418.     /* Loop until the network interface provides a message, or timeout */
  419.     for( ;; ) {
  420.         ldv_error = ldv_read( ni_handle, &msg_in, sizeof( msg_in ) );
  421.         /* Check for network interface input */
  422.  
  423.         if( ldv_error == LDV_OK ) break;
  424.  
  425.         if( ldv_error != LDV_NO_MSG_AVAIL
  426.          && ldv_error != LDV_DEVICE_BUSY ) break;   // non-recoverable
  427.  
  428.         if( ! wait || time( NULL ) > deadline )
  429.                 return( NI_TIMEOUT );       /* no message received */
  430.     }
  431.  
  432.     if( ldv_error != LDV_OK ) {
  433.         /* Network driver returned error, print it, and reopen driver */
  434.         ni_ldv_error_display( "Network driver error on read", ldv_error );
  435.         if ( ni_init( current_device_name ) != NI_OK )
  436.             printf( "\nCould not reopen network interface.\n" );
  437.         else
  438.             printf( "\nReopened network interface.\n" );
  439.         return( NI_DRIVER_ERROR );
  440.     }
  441.  
  442.     if( msg_in.ni_hdr.q.q_cmd == niCOMM ) {     // incoming message
  443.         if( verbose_flag ) {
  444.             printf( "\nReceived a LONTALK message, error = %d\n", ldv_error );
  445.             if( ldv_error == LDV_OK )  ni_msg_display( &msg_in );
  446.         }
  447.         return( NI_OK );
  448.     }
  449.         // something other than an incoming message
  450.  
  451.     if( msg_in.ni_hdr.noq.cmd == niRESET )
  452.     {
  453.         printf( "Received uplink local reset\n" );
  454.         ni_send_immediate( niFLUSH_CANCEL );
  455.     }
  456.     else
  457.         printf( "Received uplink command 0x%x\n", msg_in.ni_hdr.noq.cmd );
  458.  
  459.     return( NI_UPLINK_CMD );  /* not a message */
  460. }
  461.  
  462. /*
  463.  ****************************************************************************
  464.  * ni_put_msg().  Send the message assembled in msg_out.
  465.  ****************************************************************************
  466.  */
  467.  
  468. NI_Code ni_put_msg( void )
  469. {
  470.     LDVCode ldv_error = LDV_OK;
  471.     time_t  deadline;
  472.  
  473.     deadline =  time( NULL ) + niWAIT_TIME;
  474.  
  475.     /* Loop until the network interface accepts the output, or timeout. */
  476.     for( ;; ) {
  477.         ldv_error = ldv_write( ni_handle, &msg_out,
  478.                                 msg_out.ni_hdr.q.length + sizeof( NI_Hdr ) );
  479.             /* Attempt to write to the network interface. */
  480.  
  481.         if( ldv_error == LDV_OK ) break;
  482.         if( ldv_error != LDV_NO_BUF_AVAIL
  483.          && ldv_error != LDV_DEVICE_BUSY ) break;    // non-recoverable
  484.                 /* exit loop for fatal err */
  485.         if ( time( NULL ) > deadline )             // see if deadline passed
  486.             /* No response from network interface. */
  487.             return( NI_TIMEOUT );
  488.     }
  489.  
  490.     if( verbose_flag ) {
  491.         printf( "\nSent a LONTALK message, error = %d\n", ldv_error );
  492.         if( ldv_error == LDV_OK )
  493.             ni_msg_display( &msg_out );
  494.     }
  495.  
  496.     if( ldv_error == LDV_OK ) return( NI_OK );
  497.  
  498.         /* Network driver returned error, print it, and reopen driver */
  499.     ni_ldv_error_display( "Network driver error on write", ldv_error );
  500.     if ( ni_init( current_device_name ) != NI_OK )
  501.             printf( "\nCould not reopen network interface.\n" );
  502.     else
  503.             printf( "\nReopened network interface.\n" );
  504.     return( NI_DRIVER_ERROR );
  505. }
  506.  
  507. /*
  508.  ****************************************************************************
  509.  * ni_msg_hdr_init().  Initialize an outgoing application buffer
  510.  * using explicit addressing.
  511.  ****************************************************************************
  512.  */
  513.  
  514. void ni_msg_hdr_init( int msg_size, ServiceType service, boolean priority,
  515.         boolean local, boolean auth, boolean implicit, byte msg_tag )
  516. {
  517.  
  518.     const static NI_Queue queue[ 2 ][ 2 ] =         /* define MIP queue */
  519.         { { niTQ, niTQ_P }, { niNTQ, niNTQ_P } };
  520.  
  521.     msg_out.ni_hdr.q.queue  = queue[ service == UNACKD ][ priority ];
  522.                 /* Transaction queue            */
  523.  
  524.     msg_out.ni_hdr.q.q_cmd    = local ? niNETMGMT : niCOMM;
  525.              /* Data transfer for network interface or network         */
  526.     msg_out.ni_hdr.q.length   = sizeof( ExpMsgHdr ) + sizeof( ExplicitAddr )
  527.                                 + msg_size; /* Header size                  */
  528.  
  529.     msg_out.msg_hdr.exp.tag       = msg_tag;
  530.     msg_out.msg_hdr.exp.auth      = auth;
  531.     msg_out.msg_hdr.exp.st        = service;
  532.     msg_out.msg_hdr.exp.msg_type  = 0;      /* MIP doesn't process NVs      */
  533.     msg_out.msg_hdr.exp.response  = 0;      /* Not a response message       */
  534.     msg_out.msg_hdr.exp.pool      = 0;      /* Must be zero                 */
  535.     msg_out.msg_hdr.exp.alt_path  = 0;      /* Use default path             */
  536.     msg_out.msg_hdr.exp.addr_mode = ! implicit;   /* Addressing?            */
  537.     msg_out.msg_hdr.exp.cmpl_code = MSG_NOT_COMPL; /* Zero                  */
  538.     msg_out.msg_hdr.exp.path      = 0;      /* Use primary path             */
  539.     msg_out.msg_hdr.exp.priority  = priority;
  540.     msg_out.msg_hdr.exp.length    = msg_size;
  541.                                             /* Message size                 */
  542. }
  543.  
  544. /*************************/
  545.  
  546. void print_array( const void * data, int length, const char * format ) {
  547.     int i;
  548.     byte * ptr;
  549.  
  550.     for( i = 0, ptr = ( byte * ) data; i < length; i++, ptr++ )
  551.         printf( format, * ptr );
  552. }
  553.  
  554. /*
  555.  ****************************************************************************
  556.  * ni_msg_display().  Display contents of a network interface message.
  557.  ****************************************************************************
  558.  */
  559.  
  560. void ni_msg_display( ExpAppBuffer * msg_ptr )
  561. {
  562.     int length;
  563.  
  564.     static const char * cmd_str[ 16 ] = {
  565.         "NULL", "COMM", "NETMGMT", "TIMEOUT", "CRC", "RESET", "FLUSH_C",
  566.         "ONLINE", "OFFLINE", "FLUSH", "FLUSH_IGN", "SLEEP", "(N)ACK",
  567.         "0xD", "0xE", "DRV_CMD" };
  568.  
  569.     static const char * queue_str[ 16 ] = {
  570.         "0x0", "0x1", "TQ", "TQ_P", "NTQ", "NTQ_P", "RESPONSE", "0x7",
  571.         "INCOMING", "0x9", "0xA", "0xB", "0xC", "0xD", "0xE", "0xF" };
  572.  
  573.     static const char * compl_str[ 4 ] = {
  574.         "NOT_COMPL", "SUCCEEDS", "FAILS", "cmpl=3" };
  575.  
  576.     extern const char * svc_table[ ];       // strings for service type
  577.  
  578.     /* Display headers. */
  579.     printf("  Network intfc header: command = ni%s, queue = ni%s, "
  580.               "total length = %d\n", cmd_str[ msg_ptr->ni_hdr.q.q_cmd ],
  581.               queue_str[ msg_ptr->ni_hdr.q.queue ], msg_ptr->ni_hdr.q.length);
  582.  
  583.     printf("  Message header: tag = %d, service = %s, response = %s, "
  584.               "data length = %d\n", msg_ptr->msg_hdr.exp.tag,
  585.               svc_table[ msg_ptr->msg_hdr.exp.st ],
  586.               msg_ptr->msg_hdr.exp.response ? "yes": "no",
  587.               msg_ptr->msg_hdr.exp.length );
  588.  
  589.     printf(" Explicit address mode = %s, completion code = MSG_%s\n",
  590.               msg_ptr->msg_hdr.exp.addr_mode ? "yes" : "no",
  591.               compl_str[ msg_ptr->msg_hdr.exp.cmpl_code ] );
  592.  
  593.     /* Display address field */
  594.     printf( "  Address field (values in hex):\n" );
  595.     print_array( &msg_ptr->addr, sizeof( ExplicitAddr ), "%02X " );
  596.     printf( "\n" );
  597.  
  598.     /* Display data field. */
  599.     length = msg_ptr->ni_hdr.q.length
  600.         - sizeof( MsgHdr ) - sizeof( ExplicitAddr );
  601.     if( msg_ptr->msg_hdr.exp.length < length )
  602.         length = msg_ptr->msg_hdr.exp.length;
  603.     if( length ) {
  604.         printf("  Data field (values in hex):\n" );
  605.         print_array( &msg_ptr->data, length, "%02X " );
  606.         printf( "\n" );
  607.     }
  608. }
  609.  
  610. /*
  611.  ****************************************************************************
  612.  * handle_error - report errors from a LonTalk message. Checks ni_error
  613.  * against NI_OK, completion against MSG_SUCCEEDS, and checks response_code
  614.  * for a successful network management response bit
  615.  * (use NO_CHECK if it's not a network management message, or not a response)
  616.  * Returns FALSE if everything is OK, TRUE if some error occurred.
  617.  ****************************************************************************
  618.  */
  619.  
  620. boolean handle_error( NI_Code   ni_error,
  621.                       ComplType completion,
  622.                       byte      response_code,
  623.                       const char      * msg_name ) {
  624.  
  625.     if( ni_error != NI_OK ) {
  626.         printf( "Network error: " );
  627.         ni_error_display( msg_name, ni_error );
  628.         return TRUE;
  629.     }
  630.     if( completion == MSG_FAILS ) {
  631.         printf( "Message failed completion: %s\n", msg_name );
  632.         return TRUE;
  633.     }
  634.     if( !( response_code & 0x20 ) ) {
  635.         printf( "Response error: %s\n", msg_name );
  636.         return TRUE;
  637.     }
  638.     return FALSE;
  639. }
  640.  
  641. /*
  642.  ****************************************************************************
  643.  * ni_init().  Initialize the network interface.  Called on
  644.  * program startup and when network interface errors occur.  Network
  645.  * interface errors can be caused by cycling power on an SLTA with
  646.  * autobaud selected while this program is running.  Reopening the network
  647.  * driver will reinitialize the bit rate on the SLTA interface.
  648.  ****************************************************************************
  649.  */
  650.  
  651. NI_Code ni_init( const char *device_name )
  652. {
  653.     NI_Code ni_error = NI_OK;
  654.  
  655.     if( ni_handle >= 0 )
  656.         /* Network interface has already been opened, close it first. */
  657.         ldv_close( ni_handle );
  658.  
  659.     /* Open network interface. */
  660.     if( LDV_OK != ldv_open( device_name, &ni_handle ) )
  661.         return( NI_DRIVER_NOT_OPEN );
  662.  
  663.     /* Empty out any uplink messages */
  664.  
  665.     do {
  666.         ni_error = ni_get_msg( 1 );
  667.     } while ( ni_error == NI_OK || ni_error == NI_UPLINK_CMD );
  668.  
  669.     /* Reset the network interface. */
  670.     ni_error = ni_reset();
  671.     if (ni_error != NI_OK) {
  672.         /* Network driver returned error, print it and return. */
  673.         ni_error_display("Network interface error on reset", ni_error);
  674.         return(NI_DRIVER_NOT_RESET);
  675.     } else
  676.         current_device_name = device_name;
  677.  
  678.     return(ni_error);
  679. }
  680.  
  681. /*
  682.  ****************************************************************************
  683.  * ni_close().  Close network interface.
  684.  ****************************************************************************
  685.  */
  686.  
  687. void ni_close( void ) {
  688.     ldv_close( ni_handle );
  689. }
  690.  
  691. /*
  692.  ****************************************************************************
  693.  * ni_reset().  Reset network interface.  Wait for response.  Return error
  694.  * code.
  695.  ****************************************************************************
  696.  */
  697.  
  698. NI_Code ni_reset(void)
  699. {
  700.     LDVCode ldv_error = LDV_OK;
  701.     NI_Code ni_error  = NI_OK;
  702.     time_t  deadline;
  703.  
  704.     init_pending_list( );       /* throw away any unprocessed messages */
  705.  
  706.     if (verbose_flag)
  707.         printf( "\nReset network interface.\n" );
  708.     ni_error = ni_send_immediate( niRESET );
  709.     if( ni_error != NI_OK )
  710.         return ni_error;
  711.  
  712.     deadline = time( NULL ) + niWAIT_TIME;
  713.  
  714.     do {
  715.         /* Loop until an input is received from the network interface. */
  716.         do {
  717.             /* Check for timeout. */
  718.             if ( time( NULL ) > deadline )
  719.                 /* No response from network interface. */
  720.                 return(NI_TIMEOUT);
  721.  
  722.             /* Check for network interface input. */
  723.             ldv_error = ldv_read( ni_handle, &msg_in, sizeof( msg_in ) );
  724.         } while (ldv_error == LDV_NO_MSG_AVAIL
  725.                  || ldv_error == LDV_DEVICE_BUSY);
  726.  
  727.         if (verbose_flag) {
  728.             printf("\nReceived a LONTALK message, error = %d\n", ldv_error);
  729.             if (ldv_error == LDV_OK)
  730.                 ni_msg_display(&msg_in);
  731.         }
  732.  
  733.         if (ldv_error != LDV_OK) {
  734.             /* Network driver returned error, display it, and return error. */
  735.             ni_ldv_error_display("Network driver error on reset", ldv_error);
  736.             return(NI_DRIVER_ERROR);
  737.         }
  738.  
  739.         if (msg_in.msg_hdr.exp.cmpl_code == MSG_FAILS)
  740.             /* Failure completion code. */
  741.             return(NI_RESET_FAILS);
  742.     } while( msg_in.ni_hdr.noq.cmd != niRESET );
  743.  
  744.     return ni_send_immediate( niFLUSH_CANCEL );  /* response */
  745. }
  746. /*
  747.  ****************************************************************************
  748.  * ni_send_immediate( ).  Send an immediate command to the network interface
  749.  ****************************************************************************
  750.  */
  751.  
  752. NI_Code ni_send_immediate( NI_NoQueueCmd command ) {
  753.     msg_out.ni_hdr.noq.cmd = command;
  754.     msg_out.ni_hdr.noq.length = 0;
  755.     return ni_put_msg( );
  756. }
  757.  
  758. /*
  759.  ****************************************************************************
  760.  * ni_error_display().  Display a network interface error message.  Display
  761.  * a user specified string first.
  762.  ****************************************************************************
  763.  */
  764.  
  765. void ni_error_display(const char *s, NI_Code ni_error)
  766. {
  767.     if ((strlen(s) + strlen(ni_error_strings[ni_error])) < 78)
  768.         printf("\n%s: %s\n", s, ni_error_strings[ni_error]);
  769.     else
  770.         /* Message too long for one line, split on two lines. */
  771.         printf("\n%s:\n    %s\n", s, ni_error_strings[ni_error]);
  772. }
  773.  
  774. /*
  775.  ****************************************************************************
  776.  * ni_ldv_error_display().  Display a network driver error message.  Display
  777.  * a user pecified string first.
  778.  ****************************************************************************
  779.  */
  780.  
  781. void ni_ldv_error_display(const char *s, LDVCode ldv_error)
  782. {
  783.     if ((strlen(s) + strlen(ldv_error_strings[ldv_error])) < 78)
  784.         printf("\n%s: %s\n", s, ldv_error_strings[ldv_error]);
  785.     else
  786.         /* Message too long for one line, split on two lines. */
  787.         printf("\n%s:\n    %s\n", s, ldv_error_strings[ldv_error]);
  788. }
  789.  
  790.